//
// Created by bjliuyong on 2021/7/11.
//

#include <sys/stat.h>
#include <sys/fcntl.h>
#include "classLoader.h"

ClassPathEntry *ClassLoader::_first_entry = NULL;
ClassPathEntry *ClassLoader::_last_entry = NULL;

ClassPathEntry::ClassPathEntry() {
    set_next(NULL);
}


bool ClassPathEntry::is_lazy() {
    return false;
}

ClassPathDirEntry::ClassPathDirEntry(const char *dir) {
    _dir = dir;
}

ClassFileStream *ClassPathDirEntry::open_stream(const char *name) {
    // construct full path name
    char path[1024];
    sprintf(path, "%s/%s", _dir, name);
    INFO_PRINT("===> %s\n", path);

    // check if file exists
    int file_handle;
    struct stat st;
    if (stat(path, &st) == 0) {
        u1 *buffer = (u1 *) alloca(st.st_size);
        file_handle = open(path, 0, 0);
        if (file_handle != -1) {
            ssize_t n = read(file_handle, buffer, st.st_size);
            if (n == st.st_size) {
                INFO_PRINT("content => %s\n ", buffer);
                return new ClassFileStream(buffer, st.st_size, _dir);
            }
        }

    }

    return NULL;
}

void ClassLoader::initialize() {
    _first_entry = new ClassPathDirEntry("/Users/bjliuyong/IdeaProjects/lemon-jvm/target/classes");
}

InstanceKlass *ClassLoader::load_classfile(const char *h_name) {
    stringStream st;
    st.print_raw(h_name);
    st.print_raw(".class");
    const char *file_name = st.as_string();
    InstanceKlass *instanceKlass = new InstanceKlass;

    // Lookup stream for parsing .class file
    ClassFileStream *stream = NULL;
    ClassPathEntry *e = NULL;
    {
        e = _first_entry;
        while (e != NULL) {
            stream = e->open_stream(file_name);
            if (stream != NULL) {
                break;
            }
            e = e->next();
        }
    }
    if (stream != NULL) {
        // class file found, parse it
        ClassFileParser parser(stream);
        return parser.parseClassFile();
    }
    return instanceKlass;
}